package glassline;

import glassline.interfaces.Conveyor;
import glassline.interfaces.Shipper;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import transducer.TChannel;
import transducer.TEvent;
import transducer.TReceiver;
import transducer.Transducer;
import agent.Agent;

public class ShipperAgent extends Agent implements TReceiver, Shipper{

	//*******
	//	DATA
	//*******

	//Objects ShipperAgent interacts with
	Transducer myTransducer;
	Conveyor c;

	//Name of shipper
	private String name;
	
	//Sensors
	public boolean enterSensor = false;
	public boolean exitSensor = false;

	//List of glass currently on shipper
	public List<MyGlass> glassQueue = Collections.synchronizedList(new ArrayList<MyGlass>());
	public List<MyGlass> finishedGlass = Collections.synchronizedList(new ArrayList<MyGlass>());

	//Enum for MyGlass
	public enum glassState{WAITING, ONCONVEYOR, DONE};

	//Private class for glass
	public class MyGlass{
		Glass g;
		public glassState state;

		public MyGlass(Glass g){
			this.g = g;
			state = glassState.WAITING;
		}
	}


	//*******
	// MESSAGES
	//*******


	@Override
	public synchronized void msgHereIsGlass(Glass g) {
		glassQueue.add(new MyGlass(g));
		stateChanged();
	}

	//*******
	//SCHEDULER
	//*******	

	@Override
	public boolean pickAndExecuteAnAction() {
		synchronized(glassQueue){
			for(MyGlass mg: glassQueue){
				if(mg.state == glassState.WAITING && !enterSensor){
					addNewGlass(mg);
					return true;
				}
			}
		}
		synchronized(glassQueue){
			for(MyGlass mg: glassQueue){
				if(mg.state == glassState.ONCONVEYOR && exitSensor){
					finishGlass(glassQueue.get(0));
					return true;
				}
			}
		}
		return false;
	}

	//*******
	//Events
	//*******	

	@Override
	public void eventFired(TChannel channel, TEvent event, Object[] args) {
		switch(event){
		case SHIPPER:
			try{
				switch((Integer)args[0]){
				case 10:
					enterSensor = false;
					stateChanged();
					break;
				case 11:
					enterSensor = true;
					stateChanged();
					break;
				case 20:
					exitSensor = false;
					stateChanged();
					break;
				case 21:
					exitSensor = true;
					stateChanged();
					break;
				default:
					throw new Exception("Invalid argument: " + args[0]);
				}
			}
			catch(Exception e){
				print(e.getMessage());
			}
			break;
		}

	}


	//*******
	//ACTIONS
	//*******

	public ShipperAgent(String name, Transducer t){
		super();
		this.name = name;
		myTransducer = t;
		myTransducer.register(this, TChannel.SENSORS);
	}
	
	private void addNewGlass(MyGlass mg){
		//sends conveyor message that its okay to send the glass and starts the conveyor on the gui
		synchronized(glassQueue){
			print("Putting new piece of glass on shipper conveyor");
			myTransducer.fireEvent(TChannel.GUI, TEvent.STARTSHIPPERCONVEYOR, null);
			mg.state = glassState.ONCONVEYOR;
			c.msgIamDoneToShipper();
			stateChanged();
			return;
		}
	}
	
	private void finishGlass(MyGlass mg){
		synchronized(glassQueue){
			synchronized(finishedGlass){
				print("Finishing glass");
				myTransducer.fireEvent(TChannel.GUI, TEvent.STOPSHIPPERCONVEYOR, null); // this is sort of redundant.
				//if possible have gui just stop the conveyor when the transducer sends GLASSDONE
				
				//Removes glass from glassQueue and sets it to done
				MyGlass tempGlass = mg;
				glassQueue.remove(mg);
				tempGlass.state = glassState.DONE;
				finishedGlass.add(tempGlass);
				
				//Tells GUI that the glass is finished
				myTransducer.fireEvent(TChannel.GUI, TEvent.GLASSDONE, null);
				stateChanged();
			}
		}
	}
	
	
	//*******
	//HACKS
	//*******
	
	public void setConveyor(Conveyor c){
		this.c = c;
	}

}
